package scuff.msg.binary

import java.nio.ByteBuffer
import scuff.DoubleDispatch
import scuff.msg.Typed

import org.junit._
import org.junit.Assert._

class TestBinary {

  var buf: ByteBuffer = _
  var outgoing: StockQuoteOut = _
  
  @Before
  def setup {
    buf = ByteBuffer.allocate(100)
    outgoing = new StockQuoteOut
  }
  
  @Test
  def bothWays {
    var ticker = ""
    var bid, ask = 0f
    val callback = new MsgCallback {
      def onMessage(msg: StockQuoteIn) {
        ticker = msg.ticker
        bid = msg.bid
        ask = msg.ask
      }
    }
    outgoing.ticker = "MSFT"
    outgoing.ask = 25.13f
    outgoing.bid = 25.12f
    outgoing.writeTo(buf)
    buf.flip()
    val reader = new Reader(callback)
    reader.read(buf)
    assertEquals("MSFT", ticker)
    assertEquals(25.12f, bid, 0f)
    assertEquals(25.13f, ask, 0f)
  }
}

class StockQuoteOut extends OutgoingMessage[Byte] {
  
  var bid, ask: Float = _
  private val _ticker = new Array[Byte](5)
  def ticker = new String(_ticker).trim
  def ticker_=(t: String) {
    var i = 0
    while (i < _ticker.length) {
      _ticker(i) = (if (i < t.length) t(i) else ' ').asInstanceOf[Byte]
      i += 1
    }
  }

  def id: Byte = 0
  val len = (1 + 2 + 5 + 4 + 4).asInstanceOf[Short]
  def writeTo(buf: ByteBuffer) {
    buf.put(id).putShort(len).put(_ticker).putFloat(bid).putFloat(ask)
  }
}

trait InMessage extends DoubleDispatch[MsgCallback] {
  var buffer: ByteBuffer = _
}

class StockQuoteIn extends InMessage {
  
  private val _ticker = new Array[Byte](5)
  
  def ticker = {
    var i = 0
    while (i < _ticker.length) {
      _ticker(i) = buffer.get(3+i)
      i += 1
    }
    new String(_ticker).trim
  }
  def bid = buffer.getFloat(8)
  def ask = buffer.getFloat(12)
  def dispatch(cb: MsgCallback) = cb.onMessage(this)
}


trait MsgCallback {
  def onMessage(msg: StockQuoteIn)
}

class Reader(val callback: MsgCallback) extends DispatchingFixedLengthMessageReader[MsgCallback] {
  private val messages: Array[InMessage] = Array(new StockQuoteIn)
  def materialize(buf: ByteBuffer) = {
    val msg = messages(buf.get(0))
    msg.buffer = buf
    msg
  }
  def messageLength(buf: ByteBuffer): Int = buf.getShort(1)
}
